/*
 * Copyright 2008 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package blms.util.expression;

import java.io.IOException;
import java.io.InputStream;

/**
 * A character stream whose source is a string.
 * 
 * @author Jonhnny Weslley
 * @version 1.00, 24/04/2008
 * @since 1.0
 */
public class StringStream extends InputStream {

	private final Object mutex = this;
	private int next;
	private final int length;
	private String content;

	/**
	 * Creates a new string stream.
	 * 
	 * @param source
	 *            String providing the character stream.
	 */
	public StringStream(final String source) {
		content = source;
		length = source.length();
	}

	/**
	 * Check to make sure that the stream has not been closed
	 */
	private void ensureOpen() throws IOException {
		if (content == null) {
			throw new IOException("Stream closed");
		}
	}

	/**
	 * Reads a single character.
	 * 
	 * @return The character read, or -1 if the end of the stream has been
	 *         reached.
	 * 
	 * @exception IOException
	 *                If an I/O error occurs
	 */
	@Override
	public int read() throws IOException {
		synchronized (mutex) {
			ensureOpen();
			if (next >= length) {
				return -1;
			}
			return content.charAt(next++);
		}
	}

	/**
	 * Closes the stream and releases any system resources associated with it.
	 * Once the stream has been closed, further read(), ready(), mark(), or
	 * reset() invocations will throw an IOException. Closing a previously
	 * closed stream has no effect.
	 */
	@Override
	public void close() throws IOException {
		content = null;
	}

}
